#!/bin/python
needed=["GongfaEffect","ChaosInteraction","DevilNest","BlackMarket"]
wish="""
sbyte ConsummateLevel
sbyte Gender
bool Transgender
bool Bisexual
bool HaveLeftArm
bool HaveRightArm
bool HaveLeftLeg
bool HaveRightLeg
sbyte Happiness
sbyte BirthMonth
short ActualAge
short CurrAge
short BaseMorality
sbyte IdealSect
sbyte LifeSkillTypeInterest
sbyte CombatSkillTypeInterest
sbyte MainAttributeInterest
sbyte LifeSkillQualificationGrowthType
sbyte CombatSkillQualificationGrowthType
byte XiangshuInfection
short Health
short BaseMaxHealth
short DisorderOfQi
GameData.Domains.Character.PreexistenceCharIds PreexistenceCharIds BaseMainAttributes BaseLifeSkillQualifications BaseCombatSkillQualifications
GameData.Domains.Character.MainAttributes BaseMainAttributes
GameData.Domains.Character.LifeSkillShorts BaseLifeSkillQualifications
GameData.Domains.Character.CombatSkillShorts BaseCombatSkillQualifications
// GameData.Domains.Character.AvatarSystem.AvatarData Avatar // 有Warning故此弃用
"""

available_wish="""
short TemplateId
byte CreatingType
sbyte Gender
short ActualAge
sbyte BirthMonth
sbyte Happiness
short BaseMorality
sbyte IdealSect
sbyte LifeSkillTypeInterest
sbyte CombatSkillTypeInterest
sbyte MainAttributeInterest
bool Transgender
bool Bisexual
sbyte XiangshuType
byte MonkType
// System.Collections.Generic.List<short> FeatureIds
GameData.Domains.Character.MainAttributes BaseMainAttributes
short Health
short BaseMaxHealth
short DisorderOfQi
bool HaveLeftArm
bool HaveRightArm
bool HaveLeftLeg
bool HaveRightLeg
GameData.Domains.Character.Injuries Injuries
int ExtraNeili
sbyte ConsummateLevel
// System.Collections.Generic.List<GameData.Domains.Character.LifeSkillItem> LearnedLifeSkills
GameData.Domains.Character.LifeSkillShorts BaseLifeSkillQualifications
sbyte LifeSkillQualificationGrowthType
GameData.Domains.Character.CombatSkillShorts BaseCombatSkillQualifications
sbyte CombatSkillQualificationGrowthType
GameData.Domains.Character.ResourceInts Resources
short LovingItemSubType
short HatingItemSubType
GameData.Domains.Character.FullName FullName
GameData.Domains.Character.MonasticTitle MonasticTitle
GameData.Domains.Character.AvatarSystem.AvatarData Avatar
// System.Collections.Generic.List<short> PotentialFeatureIds
// System.Collections.Generic.List<GameData.Domains.Character.FameActionRecord> FameActionRecords
GameData.Domains.Character.Genome Genome
GameData.Domains.Character.MainAttributes CurrMainAttributes
GameData.Domains.Character.PoisonInts Poisoned
byte[] InjuriesRecoveryProgress
int CurrNeili
short LoopingNeigong
GameData.Domains.Character.NeiliAllocation BaseNeiliAllocation
GameData.Domains.Character.NeiliAllocation ExtraNeiliAllocation
GameData.Domains.Character.NeiliProportionOfFiveElements BaseNeiliProportionOfFiveElements
int HobbyExpirationDate
bool LovingItemRevealed
bool HatingItemRevealed
sbyte LegitimateBoysCount
GameData.Domains.Map.Location BirthLocation
GameData.Domains.Map.Location Location
GameData.Domains.Item.ItemKey[] Equipment
// GameData.Domains.Character.Inventory Inventory
GameData.Domains.Character.EatingItems EatingItems
// System.Collections.Generic.List<short> _learnedCombatSkills
short[] EquippedCombatSkills
short[] CombatSkillAttainmentPanels
// System.Collections.Generic.List<GameData.Domains.Character.SkillQualificationBonus> SkillQualificationBonuses
GameData.Domains.Character.PreexistenceCharIds PreexistenceCharIds BaseMainAttributes BaseLifeSkillQualifications BaseCombatSkillQualifications
byte XiangshuInfection
short CurrAge
int Exp
byte ExternalRelationState
int KidnapperId
int LeaderId
int FactionId
// System.Collections.Generic.List<GameData.Domains.Character.Ai.PersonalNeed> PersonalNeeds
GameData.Domains.Character.Ai.ActionEnergySbytes ActionEnergies
// System.Collections.Generic.List<GameData.Domains.Character.Ai.NpcTravelTarget> NpcTravelTargets
GameData.Domains.Character.Ai.PrioritizedAction.PrioritizedActionCooldownSbytes PrioritizedActionCooldowns
short CurrAge
sbyte LifeSkillQualificationGrowthType
sbyte CombatSkillQualificationGrowthType
"""
start=r"""using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Diagnostics;
using static Utils.Logger;

namespace Utils;
public static class CharacterMod {
    static void Assert(string val, int size){
        if(size!=(int)typeof(CharacterMod).GetField(val+"_Size").GetValue(null))
            throw new Exception($"致命错误：螺舟修改了{val}的类型，这可能伴随存档的不兼容，Mod因此爆炸非常正常，请不要惊慌，只要作者没有退游，必然会及时修复。在此之前，请禁用所有修改人物特殊属性（比如性别，比如出生月）的Mod，因为它们要不然无法影响存档，要不然会因为offset错误彻底毁灭你的存档\nsize of {val} ({(int)typeof(CharacterMod).GetField(val).GetValue(null)}) != {size}");
    }
    public static Type FixedFieldInfos=typeof(GameData.Domains.Character.Character).GetNestedType("FixedFieldInfos",(BindingFlags)(-1));
"""+r"""
    public static unsafe void EarlyCheck(){
        """+"\n        ".join(['Assert("'+w.split(' ')[1]+'",sizeof('+w.split(' ')[0]+'));' for w in wish.split('\n') if ' ' in w and not '//' in w.split(' ')[0]])+"""
    }
"""
end="}"
def body(ty, Val, *influence):
    if '//' in ty:return ''
    val=Val[0].lower()+Val[1:]
    Val=Val[0].upper()+Val[1:]
    return '''
    public static FieldInfo _'''+val+'''=typeof(GameData.Domains.Character.Character).GetField("_'''+val+'''",(BindingFlags)(-1));
    public static uint '''+Val+'''_Offset = (uint)(FixedFieldInfos.GetField("'''+Val+'''_Offset").GetValue(null));
    public static int '''+Val+'''_Size = (int)(FixedFieldInfos.GetField("'''+Val+'''_Size").GetValue(null));
    public static ushort '''+Val+'''_Id=GameData.Domains.Character.CharacterHelper.FieldName2FieldId["'''+Val+'''"];
    public unsafe static void '''+val+'''(this GameData.Domains.Character.Character character, '''+ty+''' value, GameData.Common.DataContext ctx){
        _'''+val+'''.SetValue(character, value);'''+(('''
        value.Serialize(GameData.ArchiveData.OperationAdder.DynamicObjectCollection_SetFixedField<int>(character.CollectionHelperData.DomainId, character.CollectionHelperData.DataId, character.GetId(), '''+Val+'''_Offset, '''+Val+'''_Size));''') if 'GameData' in ty or '[]' in ty else ('''
        *('''+ty+'''*)GameData.ArchiveData.OperationAdder.DynamicObjectCollection_SetFixedField<int>(character.CollectionHelperData.DomainId, character.CollectionHelperData.DataId, character.GetId(), '''+Val+'''_Offset, '''+Val+'''_Size)=value;'''))+'''
        character.InvalidateSelfAndInfluencedCache('''+Val+'''_Id,ctx);'''+''.join(['''
        character.InvalidateSelfAndInfluencedCache('''+x+'''_Id,ctx);''' for x in influence if x != ''])+'''
    }
    public unsafe static void '''+val+'''(this GameData.Domains.Character.Character character, GameData.Common.DataContext ctx){
        character.'''+val+'''(('''+ty+''')_'''+val+'''.GetValue(character), ctx);
    }
    public unsafe static '''+ty+''' '''+val+'''(this GameData.Domains.Character.Character character)=> ('''+ty+''')_'''+val+'''.GetValue(character);
'''

data=start+"".join([body(*w.split(' ')) for w in wish.split('\n') if ' ' in w])+end;
for i in needed:
    with open(i+"/Utils-CharacterMod.python.CS",'w') as f:f.write(data)


